這一篇主要提到的都是關於非同步以及同步處理的方式,ES6 有提供 Promise 來處理同步非同步行為,後續也有 async await 讓非同步行為更容易處理。
Promise 其實是一個原生的構造函數,可以透過 new 來生成實例。它接受一個函式作為參數,這個參數會有 resolve 和 reject 兩個參數,分別代表成功和失敗。Promise 中總共有三種狀態,pending(等待、未完成)、resolve(成功)、reject(失敗)。Promise 的使用一般是先用 new 生成一個實例,賦給變數,之後藉由呼叫該變數直接調用,如下面的範例。我們可以在實例中去判斷 resolve 和 reject 時要執行什麼事情。調用 Promise 後可以用 then 來接續去取得 Promise 執行後回傳的結果。then 是 Promise 實例的一個方法,接受兩個回調函數作為參數(reject, resolve),執行完後會返回一個 promise 物件,因此可以用 then 再接下去,一直 then, then...。catch 是非同步異常時候會執行的事情,finally 則是無論成功失敗,都會執行的事情。
const promise = new Promise((resolve, reject) => {
if (true) {
resolve(1);//resolve 會返回一個值,這個返回的數值實際上掛在 promise 實例裡面
} else {
reject(2);
}
})
promise.then( //訪問 then,then 會返回一個新的 promise
//resolve 回調函數
value => {
console.log(value)//1,resolve 回調函數
// 成功要執行的事情
return 10
},
error => {
// 失敗要執行的事情
console.log(error)//2,reject 回調函數
return 5
}
).then(
value => {
console.log(value)//10
return 20
},
error => {
console.log(error)
return 5
}
).then(
value => {
console.log(value)//20
return 30
},
error => {
console.log(error)
return 5
}
).catch (error => {
//非同步異常
}).finally(() => {
//沒有參數
//無論失敗成功都會執行
});
這邊整理兩個一次執行多個 Promise 的方法,Promise.all 與 Promise.race。Promise.all() 會同時執行所有 Promise,並在全部完成後統一回傳陣列,這個陣列的內容也是 Promise 中 resolve 的內容,但如果當中有 reject 事件,整個 Promise 都會被視為失敗。Promise.race 可以傳入多個 Promise 事件,這個方法只會回傳第一個完成的事件。
const bikeRace = (name, time) => {
return new Promise((resolve, reject) => {
if(time > 0) {
setTimeout(() => {
let str = name + '花費' + (time / 1000) +'秒完成比賽';
resolve(str);
}, time)
} else {
let str = name + '於比賽中作弊~!!!!';
reject(str);
};
});
};
Promise.race([bikeRace('Leo', 12000), bikeRace('Jack', 9000), bikeRace('Lun', 13000), bikeRace('Willie', 30000)]).then((data) => {
// 只會回傳最快完成的 reslove 或 reject
console.log(data) // "Jack 花費 9 秒完成跑完 100 公尺"
}).catch((error) => {
console.log(error)
});
Promise.all([bikeRace('Leo', 12000), bikeRace('Jack', 9000), bikeRace('Lun', 13000), bikeRace('Willie', 30000)]).then((data) => {
// 回傳全部結果
console.log(data) //["Leo 花費 12 秒完成跑完 100 公尺", "Jack 花費 9 秒完成跑完 100 公尺", "Lun 花費 13 秒完成跑完 100 公尺", "Willie 花費 30 秒完成跑完 100 公尺"]
}).catch((error) => {
console.log(error)
});
Promise.all([bikeRace('Leo', 12000), bikeRace('Jack', 9000), bikeRace('Lun', 13000), bikeRace('Willie', 0)]).then((data) => {
// 回傳全部結果
console.log(data) //Willie跑步時閃到腰摔倒~!!!!
}).catch((error) => {
console.log(error)
});
ES8 引入了 async、await 函數讓非同步處理更為方便,async 與 await 是建構於 Promise 之上的。Promise 中完成會透過 then 來回傳,在 await 則是會等待這段函式完成後再往下繼續執行。由於 await 如果遇到錯誤就會造成停止讓後方程式碼不執行,因此通常搭配 async 使用。async 的結構非常類似 Promise,只不過他能夠將 await 包在裡面,被包在裡面的 await 就如同先前的結構一樣,會依序地執行。async 本身也是類似 Promise,在正確執行的情況下 return 會傳回 resolved 的狀態,也可以使用 then 來接收正確的資料,並使用 catch 和 finally 來執行非同步失敗及最後要執行的事情
await 接非同步處理行為,通常是接 Promise,並且會等到處理完畢回傳,才會繼續執行的程式碼。如下面的範例,await 後面接著 fetch 去發出 request,之後會返回一個 Promise,Promise 會透過 then 做處理返回我們需要的資料,直到這些事情都執行完畢,才會執行後續的程式碼。如果沒有用 then 之類的方法,得到的會是 response,並不是真的數據,必須再使用如 .json() 之類的方法做處理。
async function getApi() {
try {
const res = await fetch('./post.json').then(res => res.json());
} catch(err) {
//異步異常
console.log(err)
} finally {
console.log('done')
}
};
//調用
getApi();
async 函數是返回一個 Promise 物件,async 如果有返回值,返回值會成為 then 方法回調的函數
async function getApi() {
try {
return await fetch('./post.json');
} catch(err) {
//異步異常
console.log(err)
} finally {
console.log('done')
}
};
getApi().then(res => {
return res.json(); //async 返回的 promise 物件會在第一個 then 裡面調用
})
定義一個匿名自己執行的 async 函式
(async () => {
const res = await fetch('./post.json').then(res => res.json());
})();
//函數聲明
async function test() {
};
//函數表達式
const test = async function() {
};
//物件寫法
let obj = {
name: 'leo',
async test () {
}
};
obj.test();
//class 寫法
class TestComponent {
async test () {
}
};
const a = new Test();
a.test();
//箭頭函式
const test = async () => {
};
這一篇主要是整理 ES6 中處理非同步的方式,下一篇開始會整理 JSX 的使用方式。